Flush cout - get stdout in C#

From a C# program I start doors as a new process, with the following argument:

 

"-b " + assemblyFolder + "\\export_links_main.dxl -u " + dAuth.DOORSUsername + " -P " + dAuth.DOORSPassword

 

The dxl script runs for a few minutes. This could be annoying for the user, so I'd like to print out the dxl script's status on the UI. For this purpose, on the dxl side I redifined the print function, as Mathias Mamsch suggests (eg. here: https://www.ibm.com/developerworks/community/forums/html/topic?id=77777777-0000-0000-0000-000014528886&ps=25), but I also added the flush cout command into every print function.

On the C# side, I read the redirected stdout, but unfortunately I only receive the messages after the doors process terminated.

 

I use the following code to read the stdout:

while (true)
{
    try
    {
        Process.GetProcessById(procIDD);
        stdOutput = controlD.procD.StandardOutput.ReadToEnd();
        stdError = controlD.procD.StandardError.ReadToEnd();

        if (stdOutput != "")
        {
            string[] outputSplit = stdOutput.Split('\n');
            stdOutput = "";
            foreach(string actualLine in outputSplit)
            {
                if(actualLine.Contains("[status]"))
                {
                    try
                    {
                        statusDOORS = Int32.Parse(actualLine.Substring(8));
                    }
                    catch (FormatException e)
                    {
                        Debug.WriteLine(e.Message);
                    }
                }
                else
                {
                    stdOutput += actualLine;
                }
            }

            sendThreadStatus(stdOutput, statusDOORS);
        }
        if (stdError != "")
        {
            sendThreadStatus(stdError, statusDOORS);
        }
    }
    catch (ArgumentException)
    {
        // The process is dead.
        break;
    }
}

I think the problem is that doors doesn't flush the output when I call the function. Any idea about this?

 

Thank you!

 

Janos Murai


janos.murai - Fri Aug 05 08:15:14 EDT 2016

Re: Flush cout - get stdout in C#
Wolfgang Uhr - Fri Aug 05 10:34:15 EDT 2016

Ok, doors writes to a stream and you flush the data so that you are shure, that the data are inside the stream. But you use the c#-method ReadToEnd and this method requires that the file is closed in den dxl-script, isn't it? I think you should use Read.

Re: Flush cout - get stdout in C#
Mathias Mamsch - Fri Aug 05 10:34:39 EDT 2016

I personally would not use the console for exchanging information with a process. Consoles are a complicated thing, that will receive various buffering, dependent on how your start your process and which like to block, when trying to read when no data is there. So you can not rely very well on messages being transferred over the console. 

I would rather go with a temp directory, that you pass to the DXL where it will write its messages to files. These files you can collect from your c# process. Your sendMessage function could look like this: 

string msgDir = null; 
int msgCount  = 0

void sendMessageDir(string dir) { msgDir = dir; }

void sendMessage (string msg) {
    string fileName =  msgDir "msg" msgCount  ".txt"; 
    Stream out = write fileName
    out << msg
    close out
    msgCount++;
}

You redefine your print statements to use sendMessage instead. In C# you make a Thread that creates a temp directory, monitors it for files and generates events from the contained messages. 

 

Note 1: To avoid race conditions (file exists, but content is not written yet, but thread tries to collect the file) the C# should try to get an exclusive lock (write) on the file before reading the content. Only then you can be sure, that the file content has been written completely. 

Note 2: DOORS Streams leak an object, because there is no destructor for a stream. If you sent lots of messages, you might want to go for the eval_ version to write the message to the file, preventing Stream objects to pile up in memory. 

Hope that helps, regards, Mathias

Re: Flush cout - get stdout in C#
Mathias Mamsch - Fri Aug 05 10:37:21 EDT 2016

Mathias Mamsch - Fri Aug 05 10:34:39 EDT 2016

I personally would not use the console for exchanging information with a process. Consoles are a complicated thing, that will receive various buffering, dependent on how your start your process and which like to block, when trying to read when no data is there. So you can not rely very well on messages being transferred over the console. 

I would rather go with a temp directory, that you pass to the DXL where it will write its messages to files. These files you can collect from your c# process. Your sendMessage function could look like this: 

string msgDir = null; 
int msgCount  = 0

void sendMessageDir(string dir) { msgDir = dir; }

void sendMessage (string msg) {
    string fileName =  msgDir "msg" msgCount  ".txt"; 
    Stream out = write fileName
    out << msg
    close out
    msgCount++;
}

You redefine your print statements to use sendMessage instead. In C# you make a Thread that creates a temp directory, monitors it for files and generates events from the contained messages. 

 

Note 1: To avoid race conditions (file exists, but content is not written yet, but thread tries to collect the file) the C# should try to get an exclusive lock (write) on the file before reading the content. Only then you can be sure, that the file content has been written completely. 

Note 2: DOORS Streams leak an object, because there is no destructor for a stream. If you sent lots of messages, you might want to go for the eval_ version to write the message to the file, preventing Stream objects to pile up in memory. 

Hope that helps, regards, Mathias

By the way, If you do not like writing and deleting a lot of files and you feel like experimenting, you might want to try creating a named pipe in c# and use it from DXL and come back and write over your experience. :-)

Re: Flush cout - get stdout in C#
janos.murai - Tue Aug 09 04:19:31 EDT 2016

Wolfgang Uhr - Fri Aug 05 10:34:15 EDT 2016

Ok, doors writes to a stream and you flush the data so that you are shure, that the data are inside the stream. But you use the c#-method ReadToEnd and this method requires that the file is closed in den dxl-script, isn't it? I think you should use Read.

Thank you for your answer, it solved my problem. Finally I chose the StandardOutput.ReadLine() function, because Read() only gets one char.

Another mistake I made is that I performed a synchronous read on both of the redirected streams, that can cause miscellaneous problems according to this:

https://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput(v=vs.110).aspx#Anchor_2

Janos

Re: Flush cout - get stdout in C#
janos.murai - Tue Aug 09 04:35:51 EDT 2016

Mathias Mamsch - Fri Aug 05 10:37:21 EDT 2016

By the way, If you do not like writing and deleting a lot of files and you feel like experimenting, you might want to try creating a named pipe in c# and use it from DXL and come back and write over your experience. :-)

I see your point, the console is indeed not the easiest way.

Thank you for your advices!

The first one would be a nice solution, but to keep the status accurate I would like to send lots of (~1000) messages, that required the same amount of file creation. Besides it is too many file manipulation, another problem is the user rights. My tool's source files are under Program Files, where most of the users have no permission to write and I also do not want to create these files at a separated location.

Tough, your second advice is really promising, despite the fact that I know nothing about named pipes. I will do my research and provide some feedback if succeed.

 

Janos